package rad.framework.mda.generator.engine;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Map;

import rad.framework.mda.generator.Console;
import rad.framework.mda.generator.util.MavenHelper;
import rad.framework.mda.generator.util.StereotypeHelper;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.NamedElement;

/**
 * @author boudyacho
 *
 */
public class NamedElementProcessor implements ElementProcessor {

	public void process(Element element, boolean all, String extension,
			String plugin, String suffix, Template template,
			IProgressMonitor monitor) {
		if (all) {
			processAll(element, monitor);
		}
		if (extension != null) {
			processExtension(element, extension, monitor);
		}
		if (plugin != null) {
			processPlugin(element, plugin, monitor);
		}
		if (suffix != null) {
			processSuffix(element, suffix, monitor);
		}
		if (template != null) {
			processTemplate(element, template, monitor);
		}
	}

	protected void processAll(Element element, IProgressMonitor monitor) {
		String className = element.getClass().getName();
		Map<String, Template> list = Templates.getTemplates().get(className);
		if (list == null)
			return;
		for (Template template : list.values()) {
			processTemplate(element, template, monitor);
		}
	}

	protected void processExtension(Element element, String extension, IProgressMonitor monitor) {
		String className = element.getClass().getName();
		Map<String, Template> list = Templates.getTemplates().get(className);
		if (list == null)
			return;
		for (Template template : list.values()) {
			// extension only
			if (!template.outputPattern.endsWith("." + extension)) {
				continue;
			}
			
			// TODO skip if demand only

			processTemplate(element, template, monitor);
		}
	}

	protected void processPlugin(Element element, String plugin,
			IProgressMonitor monitor) {
		String className = element.getClass().getName();
		Map<String, Template> list = Templates.getTemplates().get(className);
		if (list == null)
			return;
		for (Template template : list.values()) {
			// plugin only
			if (!plugin.equals(template.plugin)) {
				continue;
			}

			processTemplate(element, template, monitor);
		}
	}

	protected void processSuffix(Element element, String suffix,
			IProgressMonitor monitor) {
		String className = element.getClass().getName();
		Map<String, Template> list = Templates.getTemplates().get(className);
		if (list == null)
			return;
		for (Template template : list.values()) {
			// skip if not right suffix
			if (!suffix.equals(template.projectSuffix)) {
				continue;
			}

			processTemplate(element, template, monitor);
		}
	}

	protected void processTemplate(Element element, Template template,
			IProgressMonitor monitor) {
		// double check the types match
		if (!element.getClass().getName().equals(template.modelElement)) {
			return;
		}
		if (!MavenHelper.isPluginIncluded(element, template.plugin)) {
			return;
		}
		// skip if not right stereotype
		if (!matchesStereotype(element, template)) {
			return;
		}

		// do the work
		TemplateProcessor processor = Engine.getTemplateProcessor(template);
		try {
			// log to console
			Console.getStream().print(
					((NamedElement) element).getQualifiedName() + " : "
							+ template.plugin + "/" + template.path);
			processor.generate(element, template, monitor);
		} catch (Exception e) {
			// log to console
			StringWriter sw = new StringWriter();
			PrintWriter pw = new PrintWriter(sw);
			e.printStackTrace(pw);
			Console.getStream().println(sw.toString());

			// TODO increment exception counter
			// throw new RuntimeException(element.toString() + " : "
			// + template.path, e);
		}
	}

	protected boolean matchesStereotype(Element element, Template template) {
		if (template.hasStereotype != null
				&& template.hasStereotype.length() > 0) {
			return StereotypeHelper.isStereotypeApplied(element,
					template.hasStereotype);
		}
		// no stereotype means yes
		return true;
	}
}
